﻿
using System.Text.RegularExpressions;

namespace BEPUphysicsProcess
{
    internal class Program
    {
        static void Main(string[] args)
        {
            var path = Environment.CurrentDirectory;
            path += @"\..\..\..\..\";
            Console.WriteLine(Path.GetFullPath(path));
            BEPUutilities(path);
            BEPUphysics(path);
            BEPUik(path);
            ConversionHelper(path);
            BEPUphysicsDrawer(path);
            BEPUphysicsDemos(path);
        }

        private static void BEPUphysicsDemos(string path)
        {
            //source: D:\bepuphysics1\BEPUutilities
            var sourceDirectory = path + @"..\..\bepuphysics1\BEPUphysicsDemos";
            sourceDirectory = Path.GetFullPath(sourceDirectory);
            var destinationDirectory = path + "BEPUphysicsDemos";
            destinationDirectory = Path.GetFullPath(destinationDirectory);
            CopyDirectory(sourceDirectory, destinationDirectory);
            //return;
            var files = Directory.GetFiles(destinationDirectory, "*.cs", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                var fileName = Path.GetFileName(file);
                if (fileName == "CenterOffsetDemo.cs")
                    continue;
                var textCode = File.ReadAllText(file);
                int index = 0;
            J: index = textCode.IndexOf("namespace", index);
                if (index == -1)
                {
                    Console.WriteLine($"文件：{file}没有命名空间！");
                    continue;
                }
                if (index > 0)
                {
                    if (textCode[index - 1] == '/')
                    {
                        index += 10;
                        goto J;
                    }
                }
                textCode = textCode.Insert(index, "using SoftFloat;\r\n\r\n");
                textCode = textCode.Replace(@"void IDuringForcesUpdateable.Update(float dt)", @"void IDuringForcesUpdateable.Update(sfloat dt)");
                textCode = textCode.Replace(@"Age += dt;", @"Age += (float)dt;");
                textCode = textCode.Replace(@"void IEndOfFrameUpdateable.Update(float dt)", @"void IEndOfFrameUpdateable.Update(sfloat dt)");
                textCode = textCode.Replace(@"public override bool RayCast(Ray ray, float maximumLength, out RayHit rayHit)", @"public override bool RayCast(Ray ray, sfloat maximumLength, out RayHit rayHit)");
                textCode = textCode.Replace(@"protected override void UpdateBoundingBoxInternal(float dt)", @"protected override void UpdateBoundingBoxInternal(sfloat dt)");
                textCode = textCode.Replace(@"public override void Update(float dt)", @"public override void Update(float dt)");
                textCode = textCode.Replace(@"public override void UpdateTimeOfImpact(Collidable requester, float dt)", @"public override void UpdateTimeOfImpact(Collidable requester, sfloat dt)");
                textCode = textCode.Replace(@"protected override void CalculateImpulse(Entity e, float dt, out Vector3 impulse)", @"protected override void CalculateImpulse(Entity e, sfloat dt, out Vector3 impulse)");
                textCode = textCode.Replace(@"float length = r.Length();", @"float length = (float)r.Length();");
                textCode = textCode.Replace(@"float force = dt * e.Mass * Math.Min(MaxAcceleration, Multiplier / (length * length));", @"float force = (float)dt * (float)e.Mass * Math.Min(MaxAcceleration, Multiplier / (length * length));");
                textCode = textCode.Replace(@"= Vector3.Dot", @"= (float)Vector3.Dot");
                textCode = textCode.Replace(@"dot = MathHelper.Clamp(dot * e.Mass, 0, forceMagnitude * dt);", @"dot = (float)MathHelper.Clamp(dot * e.Mass, 0, forceMagnitude * dt);");
                textCode = textCode.Replace(@"forceMagnitude = myForce.Length();", @"forceMagnitude = (float)myForce.Length();");
                if (fileName == "SimpleVoxelCollidableDemo.cs")
                    textCode = textCode.Replace(@"public override void Update(float dt)", @"public override void Update(sfloat dt)");
                textCode = textCode.Replace(@"float entityHeight = Vector3.Dot(Axis, entityPosition - position + Axis * (Height / 2));", @"float entityHeight = (float)Vector3.Dot(Axis, entityPosition - position + Axis * (Height / 2));");
                textCode = textCode.Replace(@"float velocitySquared = velocity.LengthSquared();", @"float velocitySquared = (float)velocity.LengthSquared();");
                textCode = textCode.Replace(@"cells[i, j, k] = (Math.Sin(i * 0.55f + 6f + j * -0.325f) + Math.Sin(j * 0.35f - 0.5f + MathHelper.PiOver2) + Math.Sin(k * 0.5f + MathHelper.Pi + 6 + j * 0.25f)) > 0;",
                    @"cells[i, j, k] = (Math.Sin(i * 0.55f + 6f + j * -0.325f) + Math.Sin(j * 0.35f - 0.5f + (float)MathHelper.PiOver2) + Math.Sin(k * 0.5f + (float)MathHelper.Pi + 6 + j * 0.25f)) > 0;");
                textCode = textCode.Replace(@"dot = Vector3.Dot", @"dot = (float)Vector3.Dot");
                textCode = textCode.Replace(@"dot = MathHelper.Clamp(dot * e.Mass, 0, HorizontalForce * dt);", @"dot = (float)MathHelper.Clamp(dot * (float)e.Mass, 0, HorizontalForce * dt);");
                textCode = textCode.Replace(@"dot = MathHelper.Clamp(dot * e.Mass, 0, UpwardForce * dt);", @"dot = (float)MathHelper.Clamp(dot * (float)e.Mass, 0, UpwardForce * dt);");
                textCode = textCode.Replace(@"dot = MathHelper.Clamp(dot * e.Mass, 0, InwardForce * dt);", @"dot = (float)MathHelper.Clamp(dot * (float)e.Mass, 0, InwardForce * dt);");
                textCode = textCode.Replace(@"float entityDistanceFromTornado;", @"sfloat entityDistanceFromTornado;");
                textCode = textCode.Replace(@"forceMultiplier = tornadoRadius / entityDistanceFromTornado;", @"forceMultiplier = tornadoRadius / (float)entityDistanceFromTornado;");
                textCode = textCode.Replace(@"forceMultiplier = .5f + .5f * entityDistanceFromTornado / tornadoRadius;", @"forceMultiplier = .5f + .5f * (float)entityDistanceFromTornado / tornadoRadius;");
                textCode = textCode.Replace(@"float verticalError = (float)Vector3.Dot(error, up);", @"var verticalError = Vector3.Dot(error, up);");
                textCode = textCode.Replace(@"float horizontalErrorLength = horizontalError.LengthSquared();", @"float horizontalErrorLength = (float)horizontalError.LengthSquared();");
                textCode = textCode.Replace(@"float margin = Character.Body.CollisionInformation.Shape.CollisionMargin;", @"float margin = (float)Character.Body.CollisionInformation.Shape.CollisionMargin;");
                textCode = textCode.Replace(@"float cameraDistance = ChasedEntity.Space.RayCast(new Ray(lookAt, backwards), DistanceToTarget, rayCastFilter, out result) ? result.HitData.T : DistanceToTarget;",
                    @"float cameraDistance = ChasedEntity.Space.RayCast(new Ray(lookAt, backwards), DistanceToTarget, rayCastFilter, out result) ? (float)result.HitData.T : DistanceToTarget;");
                textCode = textCode.Replace(@"grabDistance = raycastResult.HitData.T;", @"grabDistance = (float)raycastResult.HitData.T;");
                textCode = textCode.Replace(@"float FrictionBlender(float wheelFriction, float supportFriction, bool isKineticFriction, Wheel wheel)", @"sfloat FrictionBlender(sfloat wheelFriction, sfloat supportFriction, bool isKineticFriction, Wheel wheel)");
                textCode = textCode.Replace(@"public float TurnSpeed = MathHelper.Pi;", @"public float TurnSpeed = (float)MathHelper.Pi;");
                textCode = textCode.Replace(@"angle = Math.Max(Vehicle.Wheels[1].Shape.SteeringAngle - TurnSpeed * dt, -MaximumTurnAngle);", @"angle = Math.Max((float)Vehicle.Wheels[1].Shape.SteeringAngle - TurnSpeed * dt, -MaximumTurnAngle);");
                textCode = textCode.Replace(@"angle = Math.Min(Vehicle.Wheels[1].Shape.SteeringAngle + TurnSpeed * dt, MaximumTurnAngle);", @"angle = Math.Min((float)Vehicle.Wheels[1].Shape.SteeringAngle + TurnSpeed * dt, MaximumTurnAngle);");
                textCode = textCode.Replace(@"angle = Math.Max(Vehicle.Wheels[1].Shape.SteeringAngle - TurnSpeed * dt, 0);", @"angle = Math.Max((float)Vehicle.Wheels[1].Shape.SteeringAngle - TurnSpeed * dt, 0);");
                textCode = textCode.Replace(@"angle = Math.Min(Vehicle.Wheels[1].Shape.SteeringAngle + TurnSpeed * dt, 0);", @"angle = Math.Min((float)Vehicle.Wheels[1].Shape.SteeringAngle + TurnSpeed * dt, 0);");
                textCode = textCode.Replace(@"float lengthSquared = value.LengthSquared();", @"float lengthSquared = (float)value.LengthSquared();");
                textCode = textCode.Replace(@"float dot;", @"sfloat dot;");
                textCode = textCode.Replace(@"float currentPitch = (float)Math.Acos(MathHelper.Clamp(-dot, -1, 1)) - MathHelper.PiOver2;", @"float currentPitch = (float)Math.Acos((float)MathHelper.Clamp(-dot, -1, 1)) - (float)MathHelper.PiOver2;");
                textCode = textCode.Replace(@"float newPitch = MathHelper.Clamp(currentPitch + radians, -maximumPitch, maximumPitch);", @"float newPitch = (float)MathHelper.Clamp(currentPitch + radians, -maximumPitch, maximumPitch);");
                textCode = textCode.Replace(@"if (Math.Abs(dot) > 1 - Toolbox.BigEpsilon)", @"if (Math.Abs((float)dot) > 1 - Toolbox.BigEpsilon)");
                textCode = textCode.Replace(@"private float maximumPitch = MathHelper.PiOver2 * 0.99f;", @"private float maximumPitch = (float)MathHelper.PiOver2 * 0.99f;");
                textCode = textCode.Replace(@"double increment = MathHelper.TwoPi / numBoxesPerRing;", @"double increment = (float)MathHelper.TwoPi / numBoxesPerRing;");
                textCode = textCode.Replace(@"distance = (a.Position - b.Position).Length();", @"distance = (float)(a.Position - b.Position).Length();");
                textCode = textCode.Replace(@"float currentDistance = jacobian.LengthSquared();", @"float currentDistance = (float)jacobian.LengthSquared();");
                textCode = textCode.Replace(@"= MathHelper.Pi", @"= (float)MathHelper.Pi");
                textCode = textCode.Replace(@"var heights = new float[xLength, zLength];", @"var heights = new sfloat[xLength, zLength];");
                textCode = textCode.Replace(@"= MathHelper.TwoPi", @"= (float)MathHelper.TwoPi");
                textCode = textCode.Replace(@"bones[i].Bone.Mass", @"(float)bones[i].Bone.Mass");
                textCode = textCode.Replace(@"t = hit.T;", @"t = (float)hit.T;");
                textCode = textCode.Replace(@"hit.Normal.LengthSquared();", @"(float)hit.Normal.LengthSquared();");
                textCode = textCode.Replace(@"planeDirection.LengthSquared();", @"(float)planeDirection.LengthSquared();");
                textCode = textCode.Replace(@"-dot / planeDirectionLengthSquared;", @"(float)-dot / planeDirectionLengthSquared;");
                textCode = textCode.Replace(@"closestPoint.LengthSquared();", @"(float)closestPoint.LengthSquared();");
                textCode = textCode.Replace(@"float backwardsDistance = radius * (float)Math.Sqrt(1 - squaredDistance / (radius * radius));", @"float backwardsDistance = (float)radius * (float)Math.Sqrt(1 - squaredDistance / (float)(radius * radius));");
                textCode = textCode.Replace(@"float t = (halfHeight - localRay.Position.Y) / localRay.Direction.Y;", @"var t = (halfHeight - localRay.Position.Y) / localRay.Direction.Y;");
                textCode = textCode.Replace(@"hitData.T", @"(float)hitData.T");
                textCode = textCode.Replace(@"pathTime += Space.TimeStepSettings.TimeStepDuration;", @"pathTime += (float)Space.TimeStepSettings.TimeStepDuration;");
                textCode = textCode.Replace(@"get { return TankToTurretJoint.Motor.Settings.Servo.Goal; }", @"get { return (float)TankToTurretJoint.Motor.Settings.Servo.Goal; }");
                textCode = textCode.Replace(@"get { return TurretBodyToBarrelJoint.Motor.Settings.Servo.Goal; }", @"get { return (float)TurretBodyToBarrelJoint.Motor.Settings.Servo.Goal; }");
                textCode = textCode.Replace(@"MinimumPitch = -MathHelper.Pi * 0.05f;", @"MinimumPitch = (float)-MathHelper.Pi * 0.05f;");
                textCode = textCode.Replace(@"get { return Motor.Settings.VelocityMotor.GoalVelocity; }", @"get { return (float)Motor.Settings.VelocityMotor.GoalVelocity; }");
                textCode = textCode.Replace(@"= offset.LengthSquared();", @"= (float)offset.LengthSquared();");
                textCode = textCode.Replace(@"myMinimumAngle = MathHelper.Clamp(value, 0, MathHelper.Pi);", @"myMinimumAngle = (float)MathHelper.Clamp(value, 0, MathHelper.Pi);");
                textCode = textCode.Replace(@"myMaximumAngle = MathHelper.Clamp(value, 0, MathHelper.Pi);", @"myMaximumAngle = (float)MathHelper.Clamp(value, 0, MathHelper.Pi);");
                textCode = textCode.Replace(@"Vector3.Dot(Vector3.Up, myWorldUpVector)", @"(float)Vector3.Dot(Vector3.Up, myWorldUpVector)");
                textCode = textCode.Replace(@"float angle = -i * MathHelper.PiOver2 / numPads;", @"float angle = -i * (float)MathHelper.PiOver2 / numPads;");
                textCode = textCode.Replace(@"float d;", @"sfloat d;");
                textCode = textCode.Replace(@"d + plane.D;", @"(float)(d + plane.D);");
                textCode = textCode.Replace(@"float velocityAlongJacobian;", @"sfloat velocityAlongJacobian;");
                textCode = textCode.Replace(@"float changeInVelocity = -velocityAlongJacobian - biasVelocity - Softness * accumulatedImpulse;", @"float changeInVelocity = (float)(-velocityAlongJacobian - biasVelocity - Softness * accumulatedImpulse);");
                textCode = textCode.Replace(@"float relativeVelocityAlongJacobian;", @"sfloat relativeVelocityAlongJacobian;");
                textCode = textCode.Replace(@"float changeInVelocity = relativeVelocityAlongJacobian - biasVelocity - Softness * accumulatedImpulse;", @"float changeInVelocity = (float)(relativeVelocityAlongJacobian - biasVelocity - Softness * accumulatedImpulse);");
                textCode = textCode.Replace(@"float depth;", @"sfloat depth;");
                textCode = textCode.Replace(@"float previousT;", @"sfloat previousT;");
                textCode = textCode.Replace(@"float t;", @"sfloat t;");
                textCode = textCode.Replace(@"contactDepth = t;", @"contactDepth = (float)t;");
                textCode = textCode.Replace(@"var heights = new float[xLength,zLength];", @"var heights = new sfloat[xLength,zLength];");
                textCode = textCode.Replace(@"new CharacterController();", @"new CharacterController(new Vector3(), 1.7f, 1.7f * .7f, 1.7f * 0.3f, 0.6f, 0.1f, 10f, 0.8f, 1.3f, 8f, 3f, 1.5f, 1000, 6, 50, 1, 250, 4.5f, 3, 5000);");
                textCode = textCode.Replace(@"new SphereCharacterController();", @"new SphereCharacterController(new Vector3(), .85f, 10f, 0.8f, 1.3f, 8f, 1000, 6, 50, 1, 250, 4.5f, 3, 5000);");
                if (fileName != "BroadPhaseRemovalTestDemo.cs" && fileName != "DemosGame.cs")
                    textCode = textCode.Replace(@"Vector2", @"NVector2");
                textCode = textCode.Replace(@"Vector3", @"NVector3");
                textCode = textCode.Replace(@"Quaternion", @"NQuaternion");
                textCode = textCode.Replace(@"Microsoft.Xna.Framework.NVector3", @"Microsoft.Xna.Framework.Vector3");
                textCode = textCode.Replace(@"var spaceDt = Character.Space != null ? Character.Space.TimeStepSettings.TimeStepDuration : dt;", @"sfloat spaceDt = Character.Space != null ? Character.Space.TimeStepSettings.TimeStepDuration : dt;");
                textCode = textCode.Replace(@"NVector3.Transform", @"Vector3.Transform");
                textCode = textCode.Replace(@"List<NVector3> vertices", @"List<Vector3> vertices");
                textCode = textCode.Replace(@"NVector3[] tempVertices;", @"Vector3[] tempVertices;");
                textCode = textCode.Replace(@"var verticesList = new List<NVector3>();", @"var verticesList = new List<Vector3>();");
                textCode = textCode.Replace(@"var meshPartVertices = new NVector3[meshPart.NumVertices];", @"var meshPartVertices = new Vector3[meshPart.NumVertices];");
                textCode = textCode.Replace(
                    @"GetVerticesAndIndicesFromModel(Model collisionModel, out NVector3[] vertices, out int[] indices)",
                    @"GetVerticesAndIndicesFromModel(Model collisionModel, out Vector3[] vertices, out int[] indices)");
                if (Path.GetFileName(file) == "BroadPhaseRemovalTestDemo.cs")
                {
                    textCode = textCode.Replace(@"BoundingBox box = new BoundingBox(new NVector3(-500, -500, -500), new NVector3(500, 500, 500));", @"BoundingBox box = new BoundingBox(new Vector3(-500, -500, -500), new Vector3(500, 500, 500));");
                    textCode = textCode.Replace(@"NVector3 position = new NVector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X),", @"Vector3 position = new Vector3((float)(rand.NextDouble() * (box.Max.X - box.Min.X) + box.Min.X),");
                }
                textCode = textCode.Replace(@"Space", @"World");
                textCode = textCode.Replace(@"Keys.World", @"Keys.Space");
                textCode = textCode.Replace(@"typeof (CharacterPlaygroundDemo),", @"typeof (CenterOffsetDemo), typeof (CharacterPlaygroundDemo),");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                textCode = textCode.Replace(@"Microsoft.Xna.Framework.NVector2", @"Microsoft.Xna.Framework.Vector2");
                textCode = textCode.Replace($"NVector3", $"NVector3");
                textCode = textCode.Replace($"NQuaternion", $"NQuaternion");
                textCode = textCode.Replace(@"using Vector2 = BEPUutilities.Vector2;", @"using Vector2 = BEPUutilities.NVector2;");
                File.WriteAllText(file, textCode);
            }
        }

        private static void BEPUphysicsDrawer(string path)
        {
            //source: D:\bepuphysics1\BEPUutilities
            var sourceDirectory = path + @"..\..\bepuphysics1\BEPUphysicsDrawer";
            sourceDirectory = Path.GetFullPath(sourceDirectory);
            var destinationDirectory = path + "BEPUphysicsDrawer";
            destinationDirectory = Path.GetFullPath(destinationDirectory);
            CopyDirectory(sourceDirectory, destinationDirectory);
            //return;
            var files = Directory.GetFiles(destinationDirectory, "*.cs", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                var textCode = File.ReadAllText(file);
                int index = 0;
            J: index = textCode.IndexOf("namespace", index);
                if (index == -1)
                {
                    Console.WriteLine($"文件：{file}没有命名空间！");
                    continue;
                }
                if (index > 0)
                {
                    if (textCode[index - 1] == '/')
                    {
                        index += 10;
                        goto J;
                    }
                }
                textCode = textCode.Insert(index, "using SoftFloat;\r\n\r\n");
                textCode = textCode.Replace(@"float radius = capsuleShape.Radius;", @"float radius = (float)capsuleShape.Radius;");
                textCode = textCode.Replace(@"rotationAxis /= angle;", @"rotationAxis /= (float)angle;");
                textCode = textCode.Replace(@"Vector3(0, capsuleShape.Length / 2, 0);", @"Vector3(0, (float)capsuleShape.Length / 2, 0);");
                textCode = textCode.Replace(@"radius + capsuleShape.Length / 2", @"radius + (float)capsuleShape.Length / 2");
                textCode = textCode.Replace(@"-radius - capsuleShape.Length / 2", @"-radius - (float)capsuleShape.Length / 2");
                textCode = textCode.Replace(@"-coneShape.Height / 4;", @"-(float)coneShape.Height / 4;");
                textCode = textCode.Replace(@"float radius = coneShape.Radius;", @"float radius = (float)coneShape.Radius;");
                textCode = textCode.Replace(@"coneShape.Height + verticalOffset", @"(float)coneShape.Height + verticalOffset");
                textCode = textCode.Replace(@"cylinderShape.Height / 2;", @"(float)cylinderShape.Height / 2;");
                textCode = textCode.Replace(@"float radius = cylinderShape.Radius;", @"float radius = (float)cylinderShape.Radius;");
                textCode = textCode.Replace(@"LineObject.MaximumAngle", @"(float)LineObject.MaximumAngle");
                textCode = textCode.Replace(@"LineObject.MinimumAngle", @"(float)LineObject.MinimumAngle");
                textCode = textCode.Replace(@"float radius = sphereShape.Radius;", @"float radius = (float)sphereShape.Radius;");
                textCode = textCode.Replace(@"boxShape.Half", @"(float)boxShape.Half");
                textCode = textCode.Replace(@"BEPUutilities.Vector3", @"BEPUutilities.NVector3");
                textCode = textCode.Replace(@"BEPUutilities.Quaternion", @"BEPUutilities.NQuaternion");
                textCode = textCode.Replace(
                    @"Vector3 translation = Matrix3x3.Transform(DisplayedObject.LocalPosition, DisplayedObject.Entity.BufferedStates.InterpolatedStates.OrientationMatrix);",
                    @"var translation = Matrix3x3.Transform(DisplayedObject.LocalPosition, DisplayedObject.Entity.BufferedStates.InterpolatedStates.OrientationMatrix);");
                textCode = textCode.Replace(@"Space", @"World");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                textCode = textCode.Replace($"NVector2", $"NVector2");
                textCode = textCode.Replace($"NVector3", $"NVector3");
                textCode = textCode.Replace($"NQuaternion", $"NQuaternion");
                File.WriteAllText(file, textCode);
            }
        }

        private static void ConversionHelper(string path)
        {
            //source: D:\bepuphysics1\BEPUutilities
            var sourceDirectory = path + @"..\..\bepuphysics1\ConversionHelper";
            sourceDirectory = Path.GetFullPath(sourceDirectory);
            var destinationDirectory = path + "ConversionHelper";
            destinationDirectory = Path.GetFullPath(destinationDirectory);
            CopyDirectory(sourceDirectory, destinationDirectory);
            //return;
            var files = Directory.GetFiles(destinationDirectory, "*.cs", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                var textCode = File.ReadAllText(file);
                var index = textCode.IndexOf("namespace");
                if (index == -1)
                {
                    Console.WriteLine($"文件：{file}没有命名空间！");
                    continue;
                }
                textCode = textCode.Insert(index, "using SoftFloat;\r\n\r\n");
                textCode = textCode.Replace("float", "sfloat");
                textCode = textCode.Replace("double", "sfloat");
                textCode = textCode.Replace("MathF", "libm");
                textCode = textCode.Replace(@"System.Math.", @"libm.");
                textCode = textCode.Replace("Math.", "libm.");
                textCode = textCode.Replace(@"public const sfloat", @"public static sfloat");
                textCode = textCode.Replace(@"private const sfloat", @"private static sfloat");
                textCode = textCode.Replace(@"= bepuVector.", @"= (float)bepuVector.");
                textCode = textCode.Replace(@"= matrix.", @"= (float)matrix.");
                textCode = textCode.Replace(@"= quaternion.", @"= (float)quaternion.");
                textCode = textCode.Replace(@"= bepuQuaternion.", @"= (float)bepuQuaternion.");
                textCode = textCode.Replace(@"= boundingSphere.", @"= (float)boundingSphere.");
                textCode = textCode.Replace(@"= plane.", @"= (float)plane.");
                textCode = textCode.Replace(@"BEPUutilities.Vector2", @"BEPUutilities.NVector2");
                textCode = textCode.Replace(@"BEPUutilities.Vector3", @"BEPUutilities.NVector3");
                textCode = textCode.Replace(@"BEPUutilities.Quaternion", @"BEPUutilities.NQuaternion");
                textCode = textCode.Replace(@"Space", @"World");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                textCode = textCode.Replace($"NVector2", $"NVector2");
                textCode = textCode.Replace($"NVector3", $"NVector3");
                textCode = textCode.Replace($"NQuaternion", $"NQuaternion");
                File.WriteAllText(file, textCode);
            }
        }

        private static void BEPUik(string path)
        {
            //source: D:\bepuphysics1\BEPUutilities
            var sourceDirectory = path + @"..\..\bepuphysics1\BEPUik";
            sourceDirectory = Path.GetFullPath(sourceDirectory);
            var destinationDirectory = path + "BEPUik";
            destinationDirectory = Path.GetFullPath(destinationDirectory);
            CopyDirectory(sourceDirectory, destinationDirectory);
            //return;
            var files = Directory.GetFiles(destinationDirectory, "*.cs", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                var textCode = File.ReadAllText(file);
                var index = textCode.IndexOf("namespace");
                if (index == -1)
                {
                    Console.WriteLine($"文件：{file}没有命名空间！");
                    continue;
                }
                textCode = textCode.Insert(index, "using SoftFloat;\r\n\r\n");
                textCode = textCode.Replace("float", "sfloat");
                textCode = textCode.Replace("double", "sfloat");
                textCode = textCode.Replace("MathF", "libm");
                textCode = textCode.Replace(@"System.Math.", @"libm.");
                textCode = textCode.Replace("Math.", "libm.");
                textCode = textCode.Replace(@"public const sfloat", @"public static sfloat");
                textCode = textCode.Replace(@"private const sfloat", @"private static sfloat");
                textCode = textCode.Replace(@"Vector2", @"NVector2");
                textCode = textCode.Replace(@"Vector3", @"NVector3");
                textCode = textCode.Replace(@"Quaternion", @"NQuaternion");
                textCode = textCode.Replace(@"Space", @"World");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                textCode = textCode.Replace($"NVector2", $"NVector2");
                textCode = textCode.Replace($"NVector3", $"NVector3");
                textCode = textCode.Replace($"NQuaternion", $"NQuaternion");
                textCode = Regex.Replace(textCode, @"\d+\.\d+[fd]", match =>
                {
                    return $"(sfloat){match.Value}";
                });
                File.WriteAllText(file, textCode);
            }
        }

        private static void BEPUphysics(string path)
        {
            //source: D:\bepuphysics1\BEPUutilities
            var sourceDirectory = path + @"..\..\bepuphysics1\BEPUphysics";
            sourceDirectory = Path.GetFullPath(sourceDirectory);
            var destinationDirectory = path + "BEPUphysics";
            destinationDirectory = Path.GetFullPath(destinationDirectory);
            CopyDirectory(sourceDirectory, destinationDirectory);
            //return;
            var files = Directory.GetFiles(destinationDirectory, "*.cs", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                var textCode = File.ReadAllText(file);
                var index = textCode.IndexOf("namespace");
                if (index == -1)
                {
                    Console.WriteLine($"文件：{file}没有命名空间！");
                    continue;
                }
                textCode = textCode.Insert(index, "using SoftFloat;\r\n\r\n");
                textCode = textCode.Replace("float", "sfloat");
                textCode = textCode.Replace("double", "sfloat");
                textCode = textCode.Replace("MathF", "libm");
                textCode = textCode.Replace(@"System.Math.", @"libm.");
                textCode = textCode.Replace("Math.", "libm.");
                textCode = textCode.Replace(@"public const sfloat", @"public static sfloat");
                textCode = textCode.Replace(@"sfloat headThreshold = -.01f", @"sfloat headThreshold /*= -.01f*/");
                textCode = textCode.Replace(@"sfloat height = 1.7f, sfloat crouchingHeight = 1.7f * .7f, sfloat proneHeight = 1.7f * 0.3f, sfloat radius = 0.6f, sfloat margin = 0.1f, sfloat mass = 10f,",
                    @"sfloat height /*= 1.7f*/, sfloat crouchingHeight /*= 1.7f * .7f*/, sfloat proneHeight /*= 1.7f * 0.3f*/, sfloat radius /*= 0.6f*/, sfloat margin /*= 0.1f*/, sfloat mass /*= 10f*/,");
                textCode = textCode.Replace(@"sfloat maximumTractionSlope = 0.8f, sfloat maximumSupportSlope = 1.3f,", @"sfloat maximumTractionSlope /*= 0.8f*/, sfloat maximumSupportSlope /*= 1.3f*/,");
                textCode = textCode.Replace(@"sfloat standingSpeed = 8f, sfloat crouchingSpeed = 3f, sfloat proneSpeed = 1.5f, sfloat tractionForce = 1000, sfloat slidingSpeed = 6, sfloat slidingForce = 50, sfloat airSpeed = 1, sfloat airForce = 250,",
                    @"sfloat standingSpeed /*= 8f*/, sfloat crouchingSpeed /*= 3f*/, sfloat proneSpeed /*= 1.5f*/, sfloat tractionForce /*= 1000*/, sfloat slidingSpeed /*= 6*/, sfloat slidingForce /*= 50*/, sfloat airSpeed /*= 1*/, sfloat airForce /*= 250*/,");
                textCode = textCode.Replace(@"Vector3 position = new Vector3(),", @"Vector3 position /*= new Vector3()*/,");
                textCode = textCode.Replace(@"sfloat jumpSpeed = 4.5f, sfloat slidingJumpSpeed = 3,", @"sfloat jumpSpeed /*= 4.5f*/, sfloat slidingJumpSpeed /*= 3*/,");
                textCode = textCode.Replace(@"sfloat maximumGlueForce = 5000", @"sfloat maximumGlueForce /*= 5000*/");
                textCode = textCode.Replace(@"sfloat radius = .85f, sfloat mass = 10f,", @"sfloat radius /*= .85f*/, sfloat mass /*= 10f*/,");
                textCode = textCode.Replace(@"sfloat speed = 8f, sfloat tractionForce = 1000, sfloat slidingSpeed = 6, sfloat slidingForce = 50, sfloat airSpeed = 1, sfloat airForce = 250,",
                    @"sfloat speed /*= 8f*/, sfloat tractionForce /*= 1000*/, sfloat slidingSpeed /*= 6*/, sfloat slidingForce /*= 50*/, sfloat airSpeed /*= 1*/, sfloat airForce /*= 250*/,");
                textCode = textCode.Replace(@"const sfloat", @"sfloat");
                textCode = textCode.Replace(@"new CharacterContactCategorizer(maximumTractionSlope, maximumSupportSlope);", @"new CharacterContactCategorizer(maximumTractionSlope, maximumSupportSlope, -.01f);");
                textCode = textCode.Replace(@"Vector2", @"NVector2");
                textCode = textCode.Replace(@"Vector3", @"NVector3");
                textCode = textCode.Replace(@"Quaternion", @"NQuaternion");
                textCode = textCode.Replace(@"Space", @"World");
                textCode = textCode.Replace(
                    $"public NVector3? Gravity\r\n        {{\r\n            get\r\n            {{\r\n                if (hasPersonalGravity)\r\n                {{\r\n                    return personalGravity;\r\n                }}\r\n                return null;\r\n            }}\r\n            set\r\n            {{\r\n                if (value != null)\r\n                {{\r\n                    if (!hasPersonalGravity || personalGravity != value.Value)\r\n                    {{\r\n                        //Personal gravity either turned on or changed; wake up to handle it.\r\n                        activityInformation.Activate();\r\n                    }}\r\n                    hasPersonalGravity = true;\r\n                    personalGravity = value.Value;\r\n                }}\r\n                else\r\n                {{\r\n                    if (hasPersonalGravity)\r\n                    {{\r\n                        //Personal gravity turned off; wake up to handle it.\r\n                        activityInformation.Activate();\r\n                    }}\r\n                    hasPersonalGravity = false;\r\n                    personalGravity = new NVector3();\r\n                }}\r\n            }}\r\n        }}",
                    $"public NVector3 Gravity\r\n        {{\r\n            get\r\n            {{\r\n                if (hasPersonalGravity)\r\n                {{\r\n                    return personalGravity;\r\n                }}\r\n                return default;\r\n            }}\r\n            set\r\n            {{\r\n                if (value != default)\r\n                {{\r\n                    if (!hasPersonalGravity || personalGravity != value)\r\n                    {{\r\n                        //Personal gravity either turned on or changed; wake up to handle it.\r\n                        activityInformation.Activate();\r\n                    }}\r\n                    hasPersonalGravity = true;\r\n                    personalGravity = value;\r\n                }}\r\n                else\r\n                {{\r\n                    if (hasPersonalGravity)\r\n                    {{\r\n                        //Personal gravity turned off; wake up to handle it.\r\n                        activityInformation.Activate();\r\n                    }}\r\n                    hasPersonalGravity = false;\r\n                    personalGravity = new NVector3();\r\n                }}\r\n            }}\r\n        }}");
                textCode = textCode.Replace($"internal NVector3 position;", $"public NVector3 position;");
                textCode = textCode.Replace($"internal NQuaternion orientation = NQuaternion.Identity;", $"public NQuaternion orientation = NQuaternion.Identity;");
                textCode = textCode.Replace($"internal Matrix3x3 orientationMatrix = Matrix3x3.Identity;", $"public Matrix3x3 orientationMatrix = Matrix3x3.Identity;");
                textCode = textCode.Replace($"internal NVector3 linearVelocity;", $"public NVector3 linearVelocity;");
                textCode = textCode.Replace($"internal NVector3 angularVelocity;", $"public NVector3 angularVelocity;");
                textCode = textCode.Replace($"protected Collidable()", $"public bool IsTrigger;\r\n\r\n\t\tprotected Collidable()");
                textCode = textCode.Replace($"throw new ArgumentException(\"The object does not belong to this space; cannot remove it.\");", $"return; // throw new ArgumentException(\"The object does not belong to this space; cannot remove it.\");");
                textCode = textCode.Replace(
                    $"public CollisionGroup()\r\n        {{\r\n            const ulong prime = 0xd8163841;\r\n            var hash = (ulong)(base.GetHashCode());\r\n            hash = hash * hash * hash * hash * hash * prime;\r\n            hashCode = (int)(hash);\r\n        }}", 
                    $"public CollisionGroup()\r\n        {{\r\n            const ulong prime = 0xd8163841;\r\n            var hash = (ulong)(base.GetHashCode());\r\n            hash = hash * hash * hash * hash * hash * prime;\r\n            hashCode = (int)(hash);\r\n        }}\r\n\r\n        public CollisionGroup(int hashCode)\r\n        {{\r\n            this.hashCode = hashCode;\r\n        }}");
                textCode = textCode.Replace(
                    $"return a.personal > b.personal ? a.personal : b.personal;\r\n        }}",
                    $"var pairRule = a.personal > b.personal ? a.personal : b.personal;\r\n            var aLayer = a.group.GetHashCode();\r\n            var bLayer = b.group.GetHashCode();\r\n            if (IsLayerInMask(aLayer, b.IncludeLayers) || IsLayerInMask(bLayer, a.IncludeLayers))\r\n                pairRule = CollisionRule.Normal;\r\n            if (IsLayerInMask(aLayer, b.ExcludeLayers) || IsLayerInMask(bLayer, a.ExcludeLayers))\r\n                pairRule = CollisionRule.NoBroadPhase;\r\n            return pairRule;\r\n        }}\r\n\r\n        public static bool IsLayerInMask(int layer, int mask)\r\n        {{\r\n            return (mask & (1 << layer)) != 0; // 使用位运算检查层是否在掩码中\r\n        }}\r\n\r\n        public int IncludeLayers;\r\n        public int ExcludeLayers;");
                //textCode = textCode.Replace($"", $"");
                //textCode = textCode.Replace($"", $"");
                //textCode = textCode.Replace($"", $"");
                //textCode = textCode.Replace($"", $"");
                //textCode = textCode.Replace($"", $"");
                //textCode = textCode.Replace($"", $"");
                textCode = textCode.Replace($"NVector2", $"NVector2");
                textCode = textCode.Replace($"NVector3", $"NVector3");
                textCode = textCode.Replace($"NQuaternion", $"NQuaternion");
                textCode = Regex.Replace(textCode, @"\d+\.\d+[fd]", match =>
                {
                    return $"(sfloat){match.Value}";
                });
                File.WriteAllText(file, textCode);
            }
        }

        private static void BEPUutilities(string path)
        {
            //source: D:\bepuphysics1\BEPUutilities
            var sourceDirectory = path + @"..\..\bepuphysics1\BEPUutilities";
            sourceDirectory = Path.GetFullPath(sourceDirectory);
            var destinationDirectory = path + "BEPUutilities";
            destinationDirectory = Path.GetFullPath(destinationDirectory);
            CopyDirectory(sourceDirectory, destinationDirectory);
            //return;
            var files = Directory.GetFiles(destinationDirectory, "*.cs", SearchOption.AllDirectories);
            foreach (var file in files)
            {
                var fileName = Path.GetFileName(file);
                if (fileName == "Vector3Ex.cs" | fileName == "QuaternionEx.cs")
                    continue;
                var textCode = File.ReadAllText(file);
                var index = textCode.IndexOf("namespace");
                if (index == -1)
                {
                    Console.WriteLine($"文件：{file}没有命名空间！");
                    continue;
                }
                textCode = textCode.Insert(index, "using SoftFloat;\r\n\r\n");
                textCode = textCode.Replace("float", "sfloat");
                textCode = textCode.Replace("double", "sfloat");
                textCode = textCode.Replace("MathF", "libm");
                textCode = textCode.Replace(@"System.Math.", @"libm.");
                textCode = textCode.Replace("Math.", "libm.");
                textCode = textCode.Replace(@"public const sfloat", @"public static sfloat");
                textCode = textCode.Replace(@"Vector2", @"NVector2");
                textCode = textCode.Replace(@"Vector3", @"NVector3");
                textCode = textCode.Replace(@"Quaternion", @"NQuaternion");
                textCode = textCode.Replace(@"Space", @"World");
                textCode = textCode.Replace(@"public struct NVector3", @"public partial struct NVector3");
                textCode = textCode.Replace(@"public struct Vector4", @"public partial struct Vector4");
                textCode = textCode.Replace(@"public struct Vector2", @"public partial struct Vector2");
                textCode = textCode.Replace(@"public struct NQuaternion", @"public partial struct NQuaternion");
                textCode = textCode.Replace($"sfloat inverse = (sfloat)(1 / libm.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z));", $"sfloat num = libm.Sqrt(v.X * v.X + v.Y * v.Y + v.Z * v.Z);\r\n            sfloat inverse = num > 1E-05f ? (sfloat)1f / num : (sfloat)0;");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                //textCode = textCode.Replace(@"", @"");
                if (fileName == "Vector2.cs")
                {
                    textCode = textCode.Insert(textCode.IndexOf("public struct NVector2"), "[Serializable]\r\n\t");
                }
                if (fileName == "Vector3.cs")
                {
                    textCode = textCode.Insert(textCode.IndexOf("public partial struct NVector3"), "[Serializable]\r\n\t");
                }
                if (fileName == "Vector4.cs")
                {
                    textCode = textCode.Insert(textCode.IndexOf("public partial struct Vector4"), "[Serializable]\r\n\t");
                }
                if (fileName == "Quaternion.cs")
                {
                    textCode = textCode.Insert(textCode.IndexOf("public partial struct NQuaternion"), "[Serializable]\r\n\t");
                }
                textCode = Regex.Replace(textCode, @"\d+\.\d+[fd]", match =>
                {
                    return $"(sfloat){match.Value}";
                });
                textCode = textCode.Replace($"NVector2", $"NVector2");
                textCode = textCode.Replace($"NVector3", $"NVector3");
                textCode = textCode.Replace($"NQuaternion", $"NQuaternion");
                File.WriteAllText(file, textCode);
            }
        }

        static void CopyDirectory(string sourceDir, string destDir)
        {
            // 创建目标文件夹
            if (!Directory.Exists(destDir))
                Directory.CreateDirectory(destDir);

            // 复制所有文件
            foreach (string file in Directory.GetFiles(sourceDir, "*.cs"))
            {
                string destFile = Path.Combine(destDir, Path.GetFileName(file));
                File.Copy(file, destFile, true); // true 表示如果目标文件已存在，则覆盖
            }

            // 递归复制所有子文件夹
            foreach (string directory in Directory.GetDirectories(sourceDir))
            {
                var directoryInfo = new DirectoryInfo(directory);
                if (directoryInfo.Name == "obj" | directoryInfo.Name == "bin")
                    continue;
                string destSubDir = Path.Combine(destDir, Path.GetFileName(directory));
                CopyDirectory(directory, destSubDir);
            }
        }
    }
}
